<template>
    <div
        v-highlight
        v-html="content"
        class="markdown-viewer"
        v-bind="$attrs"
        :class="{'markdown-viewer-input': isInput}"
    ></div>
</template>

<script setup>
    import { marked } from "marked";
    import TurndownService from "turndown";
    import he from "he";
    import "highlight.js/styles/dark.css";
    import hljs from "highlight.js";
    import { ref, watch } from 'vue'
    import { INSTRUCT_QUICK_QUESTION } from './instruct'

    marked.setOptions({
      highlight: function (code) {
        return hljs.highlightAuto(code).value;
      }
    })

    function HTMLDecode(text) {
      var temp = document.createElement("div");
      temp.innerHTML = text;
      var output = temp.innerText || temp.textContent;
      temp = null;
      return output; 
    }

    function hasClass(htmlString, className) {
      const regex = new RegExp(`\\b${className}\\b`);
      return regex.test(htmlString);
    }

    const turndownService = new TurndownService({ br: "\n\n" })

    turndownService.addRule("tdk", {
      filter: ["TDK", "TITLE", "META", "tdk", "title", "meta"],
      replacement: function (content, node) {
        let codeBlock = he.encode(node.outerHTML);
        return `${codeBlock}`;
      },
    })

    const turndownRenderer = new marked.Renderer();

    turndownRenderer.html = function (html) {
      if(hasClass(html, 'md-origin')) return html;

      html = html.replace(/\n/g, "#---n---#");
      let markdown = turndownService.turndown(html);
      markdown = markdown.replace(/#---n---#/g, "\n");
      return markdown;
    }

    turndownRenderer.text = function(text){
      text = HTMLDecode(text)
      
      const regex = /#([^\s\n]([^#]+)?[^\s\n]?)#/g;
      // const regex = /#([^\s\n](.*?)[^\s\n])#/g;
      const matches = [...text.matchAll(regex)];

      matches.forEach(match => {
        text = text.replace(match[0], `<a href="javascript:void(0)" chref="${INSTRUCT_QUICK_QUESTION}://${match[1]}" onclick="event.preventDefault();">${match[1]}</a>`)
      })

      return text
    }

    const parseMarkdown = (markdown) => {
        return marked
          .parse(
            markdown,
            {
              renderer: turndownRenderer
            }
          )
          .replace(/<img/gi, "<img style='max-width:100%'")
    }

    const props = defineProps({
        markdown: {
            type: String,
            default: ''
        },
        input: {
            type: Boolean,
            default: false
        }
    })

    const markdown = ref(props.markdown)
    const content = ref(parseMarkdown(props.markdown))
    const isInput = ref(props.input)

    watch(() => props.markdown, (val) => {
        markdown.value = val
    })

    watch(markdown, (val) => {
        content.value = parseMarkdown(val)
    })

    watch(() => props.input, (val) => {
        isInput.value = val
    })

    defineExpose({
      parseMarkdown
    })
</script>

<style lang="less" scoped>
    @keyframes twinkle {
        0% {
            opacity: 1; //透明程度
        }

        100% {
            transform: scale(1);
            opacity: 0;
        }
    }

    .markdown-viewer-input {
        &>:last-child {
            &:after {
                content: "|";
                display: 'inline-block';
                width: 2px;
                font-weight: 900;
                color: #5a54f9;
                line-height: 24px;
                animation: 1s infinite twinkle;
            }
        }
    }
</style>